package chap_01_CompletableFuture.step_02_CompletableFuture;

import java.util.concurrent.*;

/**
 * @Description 解决 FutureTask 阻塞式 get 获取返回值的问题：CompletableFuture 的异步回调
 * @Author shihan
 * @Date 2022/9/4 10:09
 * @Version 1.0
 */
public class CompletableStudy_02 {

    /**
     * 返回结果不再阻塞获取，而是采用异步回调方式后，代码实现方式是更优雅了
     * TODO 思考：但是在正常业务场景下，如何保证异步回调的返回值能在主线程结束之前返回呢？
     * 说白了，我在接口里采用异步任务，目的是为了减少接口响应时间，但是响应结果数据在接口返回的时候还是必须要都有的；
     *
     * @param args
     */
    public static void main(String[] args) {

        // 1、建议使用自定义线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 2、创建异步任务（Supplier 方式指明异步任务的执行内容）
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int nextInt = ThreadLocalRandom.current().nextInt(10);
            System.out.println("异步任务：" + nextInt);
            if (nextInt > 3) {
                int i = 10 / 0;
            }
            return nextInt;
        }, executorService)
                // 3、whenCompletion 异步回调处理：当异步任务执行完毕后（无异常），调用 whenCompletion 方法
                // 入参一：上一步的result结果，入参二：上一步的异常
                .whenComplete((result, exception) -> {
                    // 当上一步执行没有异常时，获取返回值进行异步处理
                    if (exception == null) {
                        System.out.println("异步任务执行结果：" + result);
                    }
                })
                // 4、当异步任务执行出现异常时，执行 exceptionally 方法，参数是上一步的异常
                // Function 需要返回值，此时返回 null 即可，因为出异常了（当然也可以返回其他的特殊标识）
                .exceptionally(ex -> {
                    ex.printStackTrace();
                    System.out.println("异步任务异常信息：" + ex.getCause() + ",msg:" + ex.getMessage());
                    return null;
                });

        executorService.shutdown();

    }

}
